/** Implementation of SymbolTable Class.
 * @file 
 * @author Jeremy Schultz
 */
#include "SymbolTable.h"
#include <iostream>

//-----------------------------------------------------------------------------
// Constructor
SymbolTable::SymbolTable()	{
	newBlock();

	// The first block will hold all the Keywords
	// This should reduce the amount of space used by the symbol table
	// Also the scanner sets the Word Type, ID or KEYWORD, this 
	//  way there is a set place to look for keywords.
	insert( Word::Keywords() );
}


//-----------------------------------------------------------------------------
// Dump Symbol table 
void SymbolTable::dumpTable()	{
	map<string, Word>::iterator item;

	for (unsigned int i = 0 ; i < blocks.size(); i++) {
		cout << "++BLOCK " << i << " ++" << endl;
		for (item = blocks[i].begin(); item != blocks[i].end(); item++)	{
			cout << "key: " << setw(16) << left << item->first ;
			cout << " Word( " << item->second.toString() << " )"<< endl;
		}
		cout << "--BLOCK " << i << " --" << endl;
	}
	cout << endl;
}

//-----------------------------------------------------------------------------
// Find a word
Word* SymbolTable::find(string word)	{
	map<string, Word>::iterator item;
	for (unsigned int i = blocks.size()-1; i > 0; i--) {
		if ( (item = blocks[i].find(word) ) != blocks[i].end() )	{
			return &(item->second);
		}
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// isKeyword
bool SymbolTable::isKeyword(string word)	{
	if ( (blocks.front() ).find(word)  != (blocks.front() ).end() )	{
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
// Search all Blocks
int SymbolTable::search(string word)	{
	for (unsigned int i = blocks.size() - 1; i > 0; i--) {
		if ( blocks[i].find(word) != blocks[i].end() )	{
			return i;
		}
	}
	return -1;
}

//-----------------------------------------------------------------------------
// Push a new Block on the stack
bool SymbolTable::newBlock()	{
	map<string,Word> symTable;

	if (blocks.size() == MAX_BLOCKS) {
		return false;
	}

	// Starting offset of 2 for AR. 0,1,2 are already used
	blocks.push_back(symTable);
	offset[ blocks.size() ] = 2;
	
	return true;
}

//-----------------------------------------------------------------------------
// Pop a Block of the stack
void SymbolTable::destroyBlock()	{
	blocks.pop_back();
}

//-----------------------------------------------------------------------------
// Block Level
int SymbolTable::blockLevel()	{
	return blocks.size() - 1;
}

//-----------------------------------------------------------------------------
// Next offset
int SymbolTable::nextOffset()	{
	return ++(offset[ blocks.size() ]);
}



//-----------------------------------------------------------------------------
// Insert Word
bool SymbolTable::insert(Word* word)	{
	// If found block is the current block, give an error
	if ( search(word->Lex() ) == (int)(blocks.size() -1) ) {
		return false;

	// If word was not found in current block, then insert it
	}else  {
		word->setLevel( blocks.size() - 1 );
		( blocks.back() ).insert( make_pair(word->Lex(), *word) );
	}

	return true;
}

//-----------------------------------------------------------------------------
// Insert a list of strings
void SymbolTable::insert(const string* list)	{
	for(int i=0; !( list[i] ).empty(); i++)	{
		insert(new Word( list[i], Token::KEYWORD ) );
	}
}
